/*
 * Created by Jaren at 2021/12/13 15:31
 */
import 'dart:typed_data';

import 'package:binary/binary.dart';
import 'package:inmotion_protocol/base/vehicle_data.dart';
import 'package:inmotion_protocol/common/exceptions.dart';
import 'package:inmotion_protocol/common/product_model.dart';
import 'package:inmotion_protocol/common/product_version.dart';
import 'package:inmotion_protocol/common/response.dart';
import 'package:inmotion_protocol/lorin/bean/base/bms_info.dart';
import 'package:inmotion_protocol/lorin/bean/base/real_time_info.dart';
import 'package:inmotion_protocol/lorin/bean/base/tire_pressure_sensor.dart';
import 'package:inmotion_protocol/lorin/bean/base/vehicle_real_time_info.dart';
import 'package:inmotion_protocol/lorin/bean/common/response/response.dart';
import 'package:inmotion_protocol/lorin/bean/common/bms_info.dart';
import 'package:inmotion_protocol/lorin/bean/euc/e10/e10_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/euc/e10/e10_settings.dart';
import 'package:inmotion_protocol/lorin/bean/euc/e10/e10_statistics.dart';
import 'package:inmotion_protocol/lorin/bean/euc/e20/e20_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/euc/e20/e20_settings.dart';
import 'package:inmotion_protocol/lorin/bean/euc/e20/e20_statistics.dart';
import 'package:inmotion_protocol/lorin/bean/euc/e25/e25_bms_info.dart';
import 'package:inmotion_protocol/lorin/bean/euc/e25/e25_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/euc/e25/e25_settings.dart';
import 'package:inmotion_protocol/lorin/bean/euc/e25/e25_statistics.dart';
import 'package:inmotion_protocol/lorin/bean/euc/euc_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/euc/p6/p6_bms_info.dart';
import 'package:inmotion_protocol/lorin/bean/euc/p6/p6_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/euc/p6/p6_settings.dart';
import 'package:inmotion_protocol/lorin/bean/euc/p6/p6_statistics.dart';
import 'package:inmotion_protocol/lorin/bean/euc/p6/p6_vehicle_real_time_info.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v11/v11_bms_info.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v11/v11_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v11/v11_settings.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v11/v11_statistics.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v12/v12_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v12/v12_settings.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v12/v12_statistics.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v13/v13_bms_info.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v13/v13_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v13/v13_settings.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v13/v13_statistics.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v14/v14_bms_info.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v14/v14_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v14/v14_settings.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v14/v14_statistics.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v18/v18_bms_info.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v18/v18_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v18/v18_settings.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v18/v18_statistics.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/a1/a1_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/a1/a1_settings.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/a1/a1_statistics.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/c1/c1_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/c1/c1_settings.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/c1/c1_statistics.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/le1/le1_bms_info.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/le1/le1_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/le1/le1_settings.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/le1/le1_statistics.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/lr1/lr1_bms_info.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/lr1/lr1_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/lr1/lr1_settings.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/lr1/lr1_statistics.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/rs_velo/rs_velo_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/s1/s1_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/s1/s1_settings.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/s1/s1_statistics.dart';
import 'package:inmotion_protocol/util/byte_util.dart';

import '../bean/euc/v6/v6_real_time_data.dart';
import '../bean/euc/v6/v6_settings.dart';
import '../bean/euc/v6/v6_statistics.dart';
import '../bean/scooter/rs_velo/rs_velo_settings.dart';
import '../bean/scooter/rs_velo/rs_velo_statistics.dart';

abstract class Parser {
  /// 产品型号
  final ProductModel _productModel;

  /// 各设备版本号
  final VersionWrapper _versionWrapper;

  Parser(this._productModel, this._versionWrapper);

  RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]);

  RealTimeState parseRealTimeState(Uint8ClampedList bytes, [int offset = 0]);

  RealTimeError parseRealTimeError(Uint8ClampedList bytes, [int offset = 0]);

  AllRealTimeData parseAllRealTimeData(Uint8ClampedList bytes,
      [int offset = 0]);

  VehicleRealTimeInfo parseVehicleRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var info = CommonVehicleRealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]);

  List<TirePressureSensor> parseTirePressureSensors(
      Uint8ClampedList bytes, [int offset = 0]) {
    List<TirePressureSensor> sensors = [];
    int count = (bytes.length - offset) ~/ TirePressureSensor.length();
    for (int i = 0; i < count; i++) {
      TirePressureSensor sensor = TirePressureSensor.fromBytes(
          bytes.sublist(offset + i * TirePressureSensor.length(),
              offset + (i + 1) * TirePressureSensor.length()));
      if(sensor.signalLevel != '0') {
        sensors.add(sensor);
      }
      // sensors.add(TirePressureSensor.fromBytes(
      //     bytes.sublist(offset + i * TirePressureSensor.length(),
      //         offset + (i + 1) * TirePressureSensor.length())));
    }
    print('sensor: ${sensors.first.toString()}');
    return sensors;
  }

  newVehicleRealTimeData(info, state, error);

  StatisticsResponse parseHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]);

  HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]);

  StatisticsInfoResponse parseStatisticsInfo(Uint8ClampedList bytes,
      [int offset = 0]);

  TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]);

  AbsBatteryRealTimeInfo parseBatteryRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]);

  Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]);

  SettingsResponse parseSettingsResponse(Uint8ClampedList bytes,
      [int offset = 0, bool isScreenUpdate = false]);

  AbsCalibrationResultResponse parseCalibrationResultResponse(
      Uint8ClampedList bytes,
      [int offset = 0]);

  AbsBMSCellsVoltage parseBMSCellsVoltage(Uint8ClampedList bytes,
      [int offset = 0]);

  BMSFixedInfo parseBMSFixedInfo(Uint8ClampedList bytes, [int offset = 0]);

  BMSAllRealTimeInfo parseBMSAllRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]);
}

abstract class LorinParser extends Parser {
  LorinParser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  SettingsResponse parseSettingsResponse(Uint8ClampedList bytes,
      [int offset = 0, bool isScreenUpdate = false]) {
    if (isScreenUpdate) {
      print("✅✅✅✅ = 开始屏幕升级 - 解析响应 = bytes = $bytes");
      if (bytes.length < 4) {
        return SettingsResponse.timeout();
      } else {
        if (bytes[3] == 0x80) {
          return SettingsResponse.success();
        } else {
          return SettingsResponse.notNow();
        }
      }
    } else {
      if (offset >= bytes.length) return SettingsResponse.protocolError();
      if (bytes[offset] == 0) return SettingsResponse.success();
      if (bytes[offset] == 1) {
        return SettingsResponse(
            Error.successCached, _productModel, _versionWrapper);
      }
      if (bytes[offset] == 2) {
        return SettingsResponse(
            Error.repeatedOperation, _productModel, _versionWrapper);
      }
      if (bytes[offset] == 3) {
        return SettingsResponse(
            Error.invalidParam, _productModel, _versionWrapper);
      }
      if (bytes[offset] == 4) {
        return SettingsResponse(
            Error.unsupported, _productModel, _versionWrapper);
      }
      if (bytes[offset] == 5) {
        return SettingsResponse(Error.notNow, _productModel, _versionWrapper);
      }
      if (bytes[offset] == 6) {
        return SettingsResponse(
            Error.noPermission, _productModel, _versionWrapper);
      }
      if (bytes[offset] == 7) {
        return SettingsResponse(
            Error.internalError, _productModel, _versionWrapper);
      }
      return SettingsResponse(Error.unknown, _productModel, _versionWrapper,
          'Error code is ' + bytes[offset].toString());
    }
  }

  @override
  AbsCalibrationResultResponse parseCalibrationResultResponse(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    throw NotSupportException('');
  }

  @override
  AllRealTimeData parseAllRealTimeData(Uint8ClampedList bytes,
      [int offset = 0]) {
    RealTimeInfo info = parseRealTimeInfo(bytes, offset);
    RealTimeState state = parseRealTimeState(bytes, offset + info.length());
    RealTimeError error =
        parseRealTimeError(bytes, offset + info.length() + state.length());
    return newAllRealTimeData(info, state, error);
  }

  newAllRealTimeData(info, state, error);

  @override
  BMSAllRealTimeInfo parseBMSAllRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    throw UnimplementedError();
  }

  @override
  AbsBMSCellsVoltage parseBMSCellsVoltage(Uint8ClampedList bytes,
      [int offset = 0]) {
    throw UnimplementedError();
  }

  @override
  BMSFixedInfo parseBMSFixedInfo(Uint8ClampedList bytes, [int offset = 0]) {
    throw UnimplementedError();
  }

  @override
  StatisticsInfoResponse parseStatisticsInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    return StatisticsInfoResponse.fromBytes(bytes, offset);
  }

  @override
  StatisticsResponse parseHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    throw UnimplementedError();
  }
}

abstract class EucParser extends LorinParser {
  EucParser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  EUCIMUCalibrationResultResponse parseCalibrationResultResponse(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    return EUCIMUCalibrationResultResponse(
        bytes[offset], bytes[offset + 1], bytes[offset + 2], null, null);
  }

  @override
  EucStatisticsResponse parseHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var rsp = EucStatisticsResponse(_versionWrapper, _productModel);
    rsp.fromBytes(bytes, offset);
    return rsp;
  }

  @override
  AbsBatteryRealTimeInfo parseBatteryRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var rsp = EUCBatteryRealTimeInfo(_productModel, _versionWrapper);
    rsp.fromBytes(bytes, offset);
    return rsp;
  }
}

class V11Parser extends EucParser {
  V11Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  V11RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = V11RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  V11RealTimeError parseRealTimeError(Uint8ClampedList bytes,
      [int offset = 0]) {
    var error = V11RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  V11RealTimeState parseRealTimeState(Uint8ClampedList bytes,
      [int offset = 0]) {
    var state = V11RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  V11HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = V11HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  V11TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = V11TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  V11Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = V11Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }

  @override
  newAllRealTimeData(info, state, error) {
    return AllV11RealTimeData(info, state, error);
  }

  @override
  V11VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = V11RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = V11RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return V11VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return V11VehicleSynthesizeRealTimeInfo(info, state, error);
  }

  @override
  V11BMSAllRealTimeInfo parseBMSAllRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsAllRealTimeInfo =
        V11BMSAllRealTimeInfo(_productModel, _versionWrapper);
    bmsAllRealTimeInfo.fromBytes(bytes, offset);
    return bmsAllRealTimeInfo;
  }

  @override
  BMSCellsVoltage parseBMSCellsVoltage(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsCellsVoltage = V11BMSCellsVoltage(_productModel, _versionWrapper);
    bmsCellsVoltage.fromBytes(bytes, offset);
    return bmsCellsVoltage;
  }

  @override
  BMSFixedInfo parseBMSFixedInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var bmsFixedInfo = BMSFixedInfo(_productModel, _versionWrapper);
    bmsFixedInfo.fromBytes(bytes, offset);
    return bmsFixedInfo;
  }
}

class V12Parser extends EucParser {
  V12Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  V12RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = V12RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  V12RealTimeError parseRealTimeError(Uint8ClampedList bytes,
      [int offset = 0]) {
    var error = V12RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  V12RealTimeState parseRealTimeState(Uint8ClampedList bytes,
      [int offset = 0]) {
    var state = V12RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  V12Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = V12Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }

  @override
  V12HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = V12HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  V12TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = V12TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  newAllRealTimeData(info, state, error) {
    return AllV12RealTimeData(info, state, error);
  }

  @override
  V12VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = V12RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = V12RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return V12VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return V12VehicleSynthesizeRealTimeInfo(info, state, error);
  }

  @override
  BMSCellsVoltage parseBMSCellsVoltage(Uint8ClampedList bytes,
      [int offset = 0]) {
    throw NotSupportException("");
  }
}

class V13Parser extends EucParser {
  V13Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  V13RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = V13RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  V13RealTimeError parseRealTimeError(Uint8ClampedList bytes,
      [int offset = 0]) {
    var error = V13RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  V13RealTimeState parseRealTimeState(Uint8ClampedList bytes,
      [int offset = 0]) {
    var state = V13RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  V13Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = V13Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }

  @override
  V13HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = V13HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  V13TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = V13TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  newAllRealTimeData(info, state, error) {
    return AllV13RealTimeData(info, state, error);
  }

  @override
  V13VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = V13RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = V13RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return V13VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return V13VehicleSynthesizeRealTimeInfo(info, state, error);
  }

  @override
  BMSAllRealTimeInfo parseBMSAllRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsAllRealTimeInfo = BMSAllRealTimeInfo(_productModel, _versionWrapper);
    bmsAllRealTimeInfo.fromBytes(bytes, offset);
    return bmsAllRealTimeInfo;
  }

  @override
  BMSCellsVoltage parseBMSCellsVoltage(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsCellsVoltage = V13BMSCellsVoltage(_productModel, _versionWrapper);
    bmsCellsVoltage.fromBytes(bytes, offset);
    return bmsCellsVoltage;
  }

  @override
  BMSFixedInfo parseBMSFixedInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var bmsFixedInfo = BMSFixedInfo(_productModel, _versionWrapper);
    bmsFixedInfo.fromBytes(bytes, offset);
    return bmsFixedInfo;
  }

  @override
  V13BatteryRealTimeInfo parseBatteryRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var rsp = V13BatteryRealTimeInfo(_productModel, _versionWrapper);
    rsp.fromBytes(bytes, offset);
    return rsp;
  }
}

class V14Parser extends EucParser {
  V14Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  V14RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = V14RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  V14RealTimeError parseRealTimeError(Uint8ClampedList bytes,
      [int offset = 0]) {
    var error = V14RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  V14RealTimeState parseRealTimeState(Uint8ClampedList bytes,
      [int offset = 0]) {
    var state = V14RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  V14Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = V14Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }

  @override
  V14HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = V14HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  V14TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = V14TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  newAllRealTimeData(info, state, error) {
    return AllV14RealTimeData(info, state, error);
  }

  @override
  V14VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = V14RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = V14RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return V14VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return V14VehicleSynthesizeRealTimeInfo(info, state, error);
  }

  @override
  V14BMSAllRealTimeInfo parseBMSAllRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsAllRealTimeInfo =
        V14BMSAllRealTimeInfo(_productModel, _versionWrapper);
    bmsAllRealTimeInfo.fromBytes(bytes, offset);
    return bmsAllRealTimeInfo;
  }

  @override
  BMSCellsVoltage parseBMSCellsVoltage(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsCellsVoltage = V14BMSCellsVoltage(_productModel, _versionWrapper);
    bmsCellsVoltage.fromBytes(bytes, offset);
    return bmsCellsVoltage;
  }

  @override
  V14BMSFixedInfo parseBMSFixedInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var bmsFixedInfo = V14BMSFixedInfo(_productModel, _versionWrapper);
    bmsFixedInfo.fromBytes(bytes, offset);
    return bmsFixedInfo;
  }

  @override
  V14BatteryRealTimeInfo parseBatteryRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var rsp = V14BatteryRealTimeInfo(_productModel, _versionWrapper);
    rsp.fromBytes(bytes, offset);
    return rsp;
  }
}

class V18Parser extends EucParser {
  V18Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  V18RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = V18RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  V18RealTimeError parseRealTimeError(Uint8ClampedList bytes,
      [int offset = 0]) {
    var error = V18RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  V18RealTimeState parseRealTimeState(Uint8ClampedList bytes,
      [int offset = 0]) {
    var state = V18RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  V18Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = V18Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }

  @override
  V18HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = V18HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  V18TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = V18TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  newAllRealTimeData(info, state, error) {
    return AllV18RealTimeData(info, state, error);
  }

  @override
  V18VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = V18RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = V18RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return V18VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return V18VehicleSynthesizeRealTimeInfo(info, state, error);
  }

  @override
  V18BMSAllRealTimeInfo parseBMSAllRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsAllRealTimeInfo =
        V18BMSAllRealTimeInfo(_productModel, _versionWrapper);
    bmsAllRealTimeInfo.fromBytes(bytes, offset);
    return bmsAllRealTimeInfo;
  }

  @override
  BMSCellsVoltage parseBMSCellsVoltage(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsCellsVoltage = V18BMSCellsVoltage(_productModel, _versionWrapper);
    bmsCellsVoltage.fromBytes(bytes, offset);
    return bmsCellsVoltage;
  }

  @override
  BMSFixedInfo parseBMSFixedInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var bmsFixedInfo = BMSFixedInfo(_productModel, _versionWrapper);
    bmsFixedInfo.fromBytes(bytes, offset);
    return bmsFixedInfo;
  }

  @override
  V18BatteryRealTimeInfo parseBatteryRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var rsp = V18BatteryRealTimeInfo(_productModel, _versionWrapper);
    rsp.fromBytes(bytes, offset);
    return rsp;
  }
}

class E20Parser extends EucParser {
  E20Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  E20RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = E20RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  E20RealTimeError parseRealTimeError(Uint8ClampedList bytes,
      [int offset = 0]) {
    var error = E20RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  E20RealTimeState parseRealTimeState(Uint8ClampedList bytes,
      [int offset = 0]) {
    var state = E20RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  E20Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = E20Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }

  @override
  E20HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = E20HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  E20TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = E20TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  newAllRealTimeData(info, state, error) {
    return AllE20RealTimeData(info, state, error);
  }

  @override
  E20VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = E20RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = E20RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return E20VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return E20VehicleSynthesizeRealTimeInfo(info, state, error);
  }
}

class E10Parser extends EucParser {
  E10Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  E10RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = E10RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  E10RealTimeError parseRealTimeError(Uint8ClampedList bytes,
      [int offset = 0]) {
    var error = E10RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  E10RealTimeState parseRealTimeState(Uint8ClampedList bytes,
      [int offset = 0]) {
    var state = E10RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  E10Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = E10Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }

  @override
  E10HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = E10HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  E10TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = E10TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  newAllRealTimeData(info, state, error) {
    return AllE10RealTimeData(info, state, error);
  }

  @override
  E10VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = E10RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = E10RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return E10VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return E10VehicleSynthesizeRealTimeInfo(info, state, error);
  }
}

class V6Parser extends EucParser {
  V6Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  V6RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = V6RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  V6RealTimeError parseRealTimeError(Uint8ClampedList bytes, [int offset = 0]) {
    var error = V6RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  V6RealTimeState parseRealTimeState(Uint8ClampedList bytes, [int offset = 0]) {
    var state = V6RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  V6Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = V6Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }

  @override
  V6HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = V6HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  V6TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = V6TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  newAllRealTimeData(info, state, error) {
    return AllV6RealTimeData(info, state, error);
  }

  @override
  V6VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = V6RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = V6RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return V6VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return V6VehicleSynthesizeRealTimeInfo(info, state, error);
  }
}

abstract class ScooterParser extends LorinParser {
  ScooterParser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  AllRealTimeData<RealTimeInfo, RealTimeState, RealTimeError>
      parseAllRealTimeData(Uint8ClampedList bytes, [int offset = 0]) {
    RealTimeInfo info = parseRealTimeInfo(bytes, offset);
    RealTimeError error = parseRealTimeError(bytes, offset + info.length());
    RealTimeState state =
        parseRealTimeState(bytes, offset + info.length() + error.length());
    return newAllRealTimeData(info, state, error);
  }

  @override
  AbsBMSCellsVoltage parseBMSCellsVoltage(Uint8ClampedList bytes,
      [int offset = 0]) {
    throw NotSupportException("");
  }

  @override
  ScooterCalibrationResultResponse parseCalibrationResultResponse(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    return ScooterCalibrationResultResponse(
        bytes[offset], _productModel, _versionWrapper);
  }

  @override
  AbsBatteryRealTimeInfo parseBatteryRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    throw NotSupportException("");
  }
}

class E25Parser extends EucParser {
  E25Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  E25RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = E25RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  E25RealTimeError parseRealTimeError(Uint8ClampedList bytes,
      [int offset = 0]) {
    var error = E25RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  E25RealTimeState parseRealTimeState(Uint8ClampedList bytes,
      [int offset = 0]) {
    var state = E25RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  E25Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = E25Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }

  @override
  E25HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = E25HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  E25TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = E25TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  newAllRealTimeData(info, state, error) {
    return AllE25RealTimeData(info, state, error);
  }

  @override
  E25VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = E25RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = E25RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return E25VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return E25VehicleSynthesizeRealTimeInfo(info, state, error);
  }

  @override
  BMSAllRealTimeInfo parseBMSAllRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsAllRealTimeInfo =
        E25BMSAllRealTimeInfo(_productModel, _versionWrapper);
    bmsAllRealTimeInfo.fromBytes(bytes, offset);
    return bmsAllRealTimeInfo;
  }

  @override
  BMSCellsVoltage parseBMSCellsVoltage(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsCellsVoltage = E25BMSCellsVoltage(_productModel, _versionWrapper);
    bmsCellsVoltage.fromBytes(bytes, offset);
    return bmsCellsVoltage;
  }

  @override
  BMSFixedInfo parseBMSFixedInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var bmsFixedInfo = BMSFixedInfo(_productModel, _versionWrapper);
    bmsFixedInfo.fromBytes(bytes, offset);
    return bmsFixedInfo;
  }

  @override
  E25BatteryRealTimeInfo parseBatteryRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var rsp = E25BatteryRealTimeInfo(_productModel, _versionWrapper);
    rsp.fromBytes(bytes, offset);
    return rsp;
  }
}

class P6Parser extends EucParser {
  P6Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  P6RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = P6RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  P6RealTimeError parseRealTimeError(Uint8ClampedList bytes, [int offset = 0]) {
    var error = P6RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  P6RealTimeState parseRealTimeState(Uint8ClampedList bytes, [int offset = 0]) {
    var state = P6RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  P6Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = P6Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }

  @override
  P6HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = P6HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  P6TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = P6TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  newAllRealTimeData(info, state, error) {
    return AllP6RealTimeData(info, state, error);
  }


  @override
  P6VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = P6VehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = P6RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = P6RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return P6VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return P6VehicleSynthesizeRealTimeInfo(info, state, error);
  }

  @override
  P6BMSAllRealTimeInfo parseBMSAllRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsAllRealTimeInfo =
        P6BMSAllRealTimeInfo(_productModel, _versionWrapper);
    bmsAllRealTimeInfo.fromBytes(bytes, offset);
    return bmsAllRealTimeInfo;
  }

  @override
  BMSCellsVoltage parseBMSCellsVoltage(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsCellsVoltage = P6BMSCellsVoltage(_productModel, _versionWrapper);
    bmsCellsVoltage.fromBytes(bytes, offset);
    return bmsCellsVoltage;
  }

  @override
  BMSFixedInfo parseBMSFixedInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var bmsFixedInfo = BMSFixedInfo(_productModel, _versionWrapper);
    bmsFixedInfo.fromBytes(bytes, offset);
    return bmsFixedInfo;
  }

  @override
  P6BatteryRealTimeInfo parseBatteryRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var rsp = P6BatteryRealTimeInfo(_productModel, _versionWrapper);
    rsp.fromBytes(bytes, offset);
    return rsp;
  }
}

class S1Parser extends ScooterParser {
  S1Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  S1RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = S1RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  S1RealTimeError parseRealTimeError(Uint8ClampedList bytes, [int offset = 0]) {
    var error = S1RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  S1RealTimeState parseRealTimeState(Uint8ClampedList bytes, [int offset = 0]) {
    var state = S1RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  S1AllRealTimeInfo newAllRealTimeData(info, state, error) {
    return S1AllRealTimeInfo(info, state, error);
  }

  @override
  S1VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = S1RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = S1RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return S1VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return S1VehicleSynthesizeRealTimeInfo(info, state, error);
  }

  @override
  S1HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = S1HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  S1TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = S1TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  S1Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = S1Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }

  @override
  ScooterCalibrationResultResponse parseCalibrationResultResponse(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    return ScooterCalibrationResultResponse(
        bytes[offset], _productModel, _versionWrapper);
  }
}

class A1Parser extends ScooterParser {
  A1Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  A1RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = A1RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  A1RealTimeError parseRealTimeError(Uint8ClampedList bytes, [int offset = 0]) {
    var error = A1RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  A1RealTimeState parseRealTimeState(Uint8ClampedList bytes, [int offset = 0]) {
    var state = A1RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  A1AllRealTimeInfo newAllRealTimeData(info, state, error) {
    return A1AllRealTimeInfo(info, state, error);
  }

  @override
  A1VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = A1RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = A1RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return A1VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return A1VehicleSynthesizeRealTimeInfo(info, state, error);
  }

  @override
  A1HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = A1HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  A1TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = A1TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  A1Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = A1Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }
}

class C1Parser extends ScooterParser {
  C1Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  C1RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = C1RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  C1RealTimeError parseRealTimeError(Uint8ClampedList bytes, [int offset = 0]) {
    var error = C1RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  C1RealTimeState parseRealTimeState(Uint8ClampedList bytes, [int offset = 0]) {
    var state = C1RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  C1AllRealTimeInfo newAllRealTimeData(info, state, error) {
    return C1AllRealTimeInfo(info, state, error);
  }

  @override
  C1VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = C1RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = C1RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return C1VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return C1VehicleSynthesizeRealTimeInfo(info, state, error);
  }

  @override
  C1HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = C1HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  C1TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = C1TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  C1Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = C1Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }
}

class LE1Parser extends ScooterParser {
  LE1Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  AllRealTimeData<RealTimeInfo, RealTimeState, RealTimeError>
      parseAllRealTimeData(Uint8ClampedList bytes, [int offset = 0]) {
    RealTimeInfo info = parseRealTimeInfo(bytes, offset);
    RealTimeState state = parseRealTimeState(bytes, offset + info.length());
    if (_productModel.isLE1V1Series()) {
      // 综合实时信息中，前大灯状态是反的，在这里屏蔽此问题
      state.headlightState =
          state.headlightState.value == 1 ? Uint4(0) : Uint4(1);
    }
    RealTimeError error =
        parseRealTimeError(bytes, offset + info.length() + state.length());

    return newAllRealTimeData(info, state, error);
  }

  @override
  LE1RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = LE1RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  LE1RealTimeError parseRealTimeError(Uint8ClampedList bytes,
      [int offset = 0]) {
    var error = LE1RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  LE1RealTimeState parseRealTimeState(Uint8ClampedList bytes,
      [int offset = 0]) {
    var state = LE1RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  LE1AllRealTimeInfo newAllRealTimeData(info, state, error) {
    return LE1AllRealTimeInfo(info, state, error);
  }

  @override
  LE1VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = LE1RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = LE1RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return LE1VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return LE1VehicleSynthesizeRealTimeInfo(info, state, error);
  }

  @override
  LE1HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = LE1HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  LE1TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = LE1TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  LE1Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = LE1Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }

  @override
  LE1BmsCellsVoltage parseBMSCellsVoltage(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsCellsVoltage = LE1BmsCellsVoltage(_productModel, _versionWrapper);
    bmsCellsVoltage.fromBytes(bytes, offset);
    return bmsCellsVoltage;
  }
}

class LR1Parser extends ScooterParser {
  LR1Parser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  AllRealTimeData<RealTimeInfo, RealTimeState, RealTimeError>
      parseAllRealTimeData(Uint8ClampedList bytes, [int offset = 0]) {
    RealTimeInfo info = parseRealTimeInfo(bytes, offset);
    RealTimeState state = parseRealTimeState(bytes, offset + info.length());
    RealTimeError error =
        parseRealTimeError(bytes, offset + info.length() + state.length());
    return newAllRealTimeData(info, state, error);
  }

  @override
  LR1RealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var info = LR1RealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  LR1RealTimeError parseRealTimeError(Uint8ClampedList bytes,
      [int offset = 0]) {
    var error = LR1RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  LR1RealTimeState parseRealTimeState(Uint8ClampedList bytes,
      [int offset = 0]) {
    var state = LR1RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  LR1AllRealTimeInfo newAllRealTimeData(info, state, error) {
    return LR1AllRealTimeInfo(info, state, error);
  }

  @override
  LR1VehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = LR1RealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = LR1RealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return LR1VehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return LR1VehicleSynthesizeRealTimeInfo(info, state, error);
  }

  @override
  LR1HistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = LR1HistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  LR1TotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = LR1TotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  LR1Settings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = LR1Settings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }

  @override
  BMSAllRealTimeInfo parseBMSAllRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsAllRealTimeInfo = BMSAllRealTimeInfo(_productModel, _versionWrapper);
    bmsAllRealTimeInfo.fromBytes(bytes, offset);
    return bmsAllRealTimeInfo;
  }

  @override
  BMSCellsVoltage parseBMSCellsVoltage(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsCellsVoltage = LR1BMSCellsVoltage(_productModel, _versionWrapper);
    bmsCellsVoltage.fromBytes(bytes, offset);
    return bmsCellsVoltage;
  }

  @override
  BMSFixedInfo parseBMSFixedInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var bmsFixedInfo = BMSFixedInfo(_productModel, _versionWrapper);
    bmsFixedInfo.fromBytes(bytes, offset);
    return bmsFixedInfo;
  }
}

class RsVeloParser extends ScooterParser {
  RsVeloParser(ProductModel productModel, VersionWrapper versionWrapper)
      : super(productModel, versionWrapper);

  @override
  AllRealTimeData<RealTimeInfo, RealTimeState, RealTimeError>
      parseAllRealTimeData(Uint8ClampedList bytes, [int offset = 0]) {
    RealTimeInfo info = parseRealTimeInfo(bytes, offset);
    RealTimeState state = parseRealTimeState(bytes, offset + info.length());
    RealTimeError error =
        parseRealTimeError(bytes, offset + info.length() + state.length());
    return newAllRealTimeData(info, state, error);
  }

  @override
  RsVeloRealTimeInfo parseRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var info = RsVeloRealTimeInfo(_productModel, _versionWrapper);
    info.fromBytes(bytes, offset);
    return info;
  }

  @override
  RsVeloRealTimeError parseRealTimeError(Uint8ClampedList bytes,
      [int offset = 0]) {
    var error = RsVeloRealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset);
    return error;
  }

  @override
  RsVeloRealTimeState parseRealTimeState(Uint8ClampedList bytes,
      [int offset = 0]) {
    var state = RsVeloRealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset);
    return state;
  }

  @override
  RsVeloAllRealTimeInfo newAllRealTimeData(info, state, error) {
    return RsVeloAllRealTimeInfo(info, state, error);
  }

  @override
  RsVeloVehicleSynthesizeRealTimeInfo parseVehicleSynthesizeRealTimeInfo(
      Uint8ClampedList bytes,
      [int offset = 0]) {
    Uint16 format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    var vehicleRealTimeInfo = CommonVehicleRealTimeInfo(
        _productModel, _versionWrapper);
    vehicleRealTimeInfo.fromBytes(bytes, offset);
    var state = RsVeloRealTimeState(_productModel, _versionWrapper);
    state.fromBytes(bytes, offset + vehicleRealTimeInfo.length());
    var error = RsVeloRealTimeError(_productModel, _versionWrapper);
    error.fromBytes(bytes, offset + vehicleRealTimeInfo.length() + state.length());
    return RsVeloVehicleSynthesizeRealTimeInfo(
        vehicleRealTimeInfo, state, error);
  }

  @override
  newVehicleRealTimeData(info, state, error) {
    return P6VehicleSynthesizeRealTimeInfo(info, state, error);
  }

  @override
  RsVeloHistoryStatistics parseSingleHistoryStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = RsVeloHistoryStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset + statistics.statisticsOffset());
    return statistics;
  }

  @override
  RsVeloTotalStatistics parseTotalStatistics(Uint8ClampedList bytes,
      [int offset = 0]) {
    var statistics = RsVeloTotalStatistics(_productModel, _versionWrapper);
    statistics.fromBytes(bytes, offset);
    return statistics;
  }

  @override
  RsVeloSettings parseSettings(Uint8ClampedList bytes, [int offset = 0]) {
    var settings = RsVeloSettings(_productModel, _versionWrapper);
    settings.fromBytes(bytes, offset);
    return settings;
  }

  @override
  BMSAllRealTimeInfo parseBMSAllRealTimeInfo(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsAllRealTimeInfo = BMSAllRealTimeInfo(_productModel, _versionWrapper);
    bmsAllRealTimeInfo.fromBytes(bytes, offset);
    return bmsAllRealTimeInfo;
  }

  @override
  BMSCellsVoltage parseBMSCellsVoltage(Uint8ClampedList bytes,
      [int offset = 0]) {
    var bmsCellsVoltage = LR1BMSCellsVoltage(_productModel, _versionWrapper);
    bmsCellsVoltage.fromBytes(bytes, offset);
    return bmsCellsVoltage;
  }

  @override
  BMSFixedInfo parseBMSFixedInfo(Uint8ClampedList bytes, [int offset = 0]) {
    var bmsFixedInfo = BMSFixedInfo(_productModel, _versionWrapper);
    bmsFixedInfo.fromBytes(bytes, offset);
    return bmsFixedInfo;
  }
}
